package com.shujia.custom.udf;

import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
import org.apache.hadoop.hive.serde2.lazy.LazyInteger;
import org.apache.hadoop.hive.serde2.lazy.LazyString;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;

/**
 * 设计模式：
 * 简单工厂模式
 * 工厂模式
 * 单例模式
 * - 懒汉式 面试的时候说懒汉式（线程安全的问题）
 * - 饿汉式 开发的时候写饿汉式
 */
public class MyGenericUDFDemo1 extends GenericUDF {
    /*
        这个方法主要是对自定义的UDF函数进行初始化，目的是指定调用完函数返回的值的类型
        需求：传入一个字符串，返回一个新的字符串
        举例：SMITH --> 数加：SMITH
     */
    @Override
    public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
        //使用PrimitiveObjectInspectorFactory工厂类，获取String类型的ObjectInspector
        return PrimitiveObjectInspectorFactory.javaStringObjectInspector;
    }

    /*
        该方法是自定义UDF的核心方法，目的是实现自定义UDF的逻辑
        是在initialize方法之后执行的

        arguments将来会有多个参数，但是UDF函数只有一个参数，所以arguments[0]就是传入的第一个参数
     */
    @Override
    public Object evaluate(DeferredObject[] arguments) throws HiveException {
        String out = "";
        DeferredObject argument = arguments[0]; // 可能是ename, 也可能是sal
        //DeferredObject存储的是传入函数的元素
        Object o = argument.get(); // Object o = ""
        //因为新版本中只有一个evaluate方法可以调用，无法重载多个
        //因为hive的数据是在来自于HDFS的，读取数据的方式都是MR的方式的读取的
        //这里的数据类型是hadoop中的数据类型
        // Text -- String
        // IntWritable -- Integer

//        out = o.getClass().getName();

        //instanceof 判断左边的对象是否是右边的类的对象或者类的子类对象
        if (o instanceof LazyString) {
            out = "数加: " + o;
        }else if(o instanceof LazyInteger){
            //向上转型
            //父 f = new 子();
            //向下转型
            //子 z = (子)f;
            //向下转型，才可以使用对应真实数据类型的功能
            LazyInteger i = (LazyInteger) o;
            int sal = i.getWritableObject().get();
            if(sal<2000){
                out =  "低薪";
            }else if(sal<3000){
                out = "中等薪资";
            }else {
                out = "高薪资";
            }
        }
        return out;
    }

    @Override
    public String getDisplayString(String[] children) {
        return "这是我们自己使用新版本写法自定义的UDF函数";
    }
}
